package movepaint;

import movepaint.stateMachine.InkMachine;
import movepaint.view.MenuMain;
import java.awt.Color;

import javax.swing.JFrame;

import java.awt.Font;
import fr.lri.swingstates.canvas.CPolyLine;
import fr.lri.swingstates.canvas.CRectangle;
import fr.lri.swingstates.canvas.CShape;
import fr.lri.swingstates.canvas.CStateMachine;
import fr.lri.swingstates.canvas.Canvas;
import fr.lri.swingstates.debug.StateMachineVisualization;
import fr.lri.swingstates.gestures.AbstractClassifier;
import fr.lri.swingstates.gestures.rubine.RubineClassifier;
import java.awt.BorderLayout;
import java.awt.Image;
import java.awt.Toolkit;
import java.io.File;
import java.util.ArrayList;
import movepaint.stateMachine.FreeDrawMachine;
import movepaint.stateMachine.HighLightMachine;
import movepaint.stateMachine.PieMenuMachine;
import movepaint.stateMachine.SelectMoveMachine;
import movepaint.view.ToolBarOutils;
import movepaint.view.StatusBar;
import movepaint.view.ToolBarCouleurs;


/**
 * Classe principale de l'application. Elle affiche la frame de l'appli
 * @author Paulino A.
 * @version 1.0
 */
public class GestureRecognition extends JFrame {
	// Menu de l'application
	public MenuMain _menu = null;
    // Toolbar d'outils
    public ToolBarOutils _toolBar = null;
    // Toolbar couleur
    public ToolBarCouleurs _toolBarCouleurs = null;
    // Canvas de dessin
    public Canvas canvas = null;
    // Barre de status
    public StatusBar _statusBar = null;
    // Fichier en cours de lecture/ecriture
    public File file = null;
    // Machine a etat du panel de dessin
    public InkMachine sm = null;
    // Machine a etat du menu
    public HighLightMachine smMenu = null;
    // Machine a etat du dessin libre
    public FreeDrawMachine smFreeDraw = null;
    // Machine a etat pour la selection/deplacement
    public SelectMoveMachine smSelectMove = null;
    // Machine a etat du pieMenu
    public PieMenuMachine smPieMenu = null;
    // Couleur actuelle pour les bordures
    public Color _borderColor = null;
    // Couleur actuelle pour le remplissage des figures
    public Color _backgroundColor = null;

    private RubineClassifier classifier = null;
    
    // TAG pour les gestes reconnus
    public final static String GESTE_TAG = "geste";

    // Icone de l'application
	public static final String ICON_APPLICATION = "iconMovePaint.gif";

    // Chemin relatif au dossier de l'application
	private static final String PATH_APPLICATION = System.getProperty("user.dir")
                                                    + File.separator;

    // Chemin relatif a la doc de l'application
    public static final String PATH_DOC = PATH_APPLICATION
                                            + "doc"
                                            + File.separator
                                            + "index.html";

    //	Chemin relatif aux gestes
	public static final String PATH_GESTES = PATH_APPLICATION
											+ "resources"
											+ File.separator
                                            + "vocabulaire.cl";

    //	Chemin relatif aux images
	public static final String PATH_IMG = PATH_APPLICATION
											+ "images"
											+ File.separator;


    // Différents mode de dessin (libre, selection/deplacement, assisté)
    public static final int MODE_DESSIN_LIBRE      = 10;
    public static final int MODE_SELECT_DEPLACE    = 11;
    public static final int MODE_ASSISTE           = 12;

    // Paramètres de la frame
    public static final int WIDTH_TOOL = 75;
    public static final int HEIGHT_TOOL = 60;
    public static final String TITLE = "Editeur graphique a reconnaissance de gestes";

    // Mode DEBUG : Affichage des machines a état
    private static final boolean MODE_DEBUG = true;

    /**
     * Constructeur de la classe
     */
    public GestureRecognition() {
        super(TITLE);

        // On change l'icone de la frame
		Image icone = Toolkit.getDefaultToolkit().getImage(PATH_IMG + ICON_APPLICATION);
		this.setIconImage(icone);
        
        // On créer tous les composants
        createComponents();

        // On organise et ajoute tous les composants
        placeComponents();

        // On active ou non le mode debug
        if (MODE_DEBUG)
            activeDebugMode();

        // Affichage de la frame
        setVisible(true);
    }

    /**
     * Affichage des machines a état pour le debugage
     */
    private void activeDebugMode() {
        // On créer unee vue des machines a état
        StateMachineVisualization smv           = new StateMachineVisualization(sm);

        ArrayList<CStateMachine> listSM = new ArrayList<CStateMachine>();
      //  listSM.add(smMenu);
        listSM.add(smFreeDraw);
     //   listSM.add(smSelectMove);
        listSM.add(smPieMenu);
        JFrame debug = null;

        // On affiche chacune des machines a etat dans une fenetre
        for (CStateMachine stateMachine: listSM) {
            debug = smv.windowVisualization(stateMachine);
            debug.setLocationRelativeTo(null);
            debug.setVisible(true);
        }
    }

    /**
     * Création des composants
     */
    private void createComponents() {
        /** Creation du menu **/
        _menu = new MenuMain(this);

        /** Creation de la barre d'outil **/
        _toolBar = new ToolBarOutils(this);

        /** Creation de la barre de couleurs **/
        _toolBarCouleurs = new ToolBarCouleurs(this);        

        /** Creation de la barre de statut **/
        _statusBar = new StatusBar();
        
        /** Creation du canvas de dessin **/
        canvas = new Canvas(600, 600);

        // Initialisation des couleurs par défaut
        _borderColor = Color.BLACK;
        _backgroundColor = Color.WHITE;
        
        // Chargement des gestes a reconnaitre
        classifier = RubineClassifier.newClassifier(PATH_GESTES);
        setSize(WIDTH_TOOL * (classifier.getClassesNames().size() + 3) + 45, 600);
        recognizedGestures(classifier);

        // Machine a état pout le Canvas
        sm = new InkMachine(classifier, canvas, this);

        // Add a canvas to the swing glasspane to draw the pie menu.
        setGlassPane(canvas);
        getGlassPane().setVisible(true);
        canvas.setOpaque(true);

        // Attach pie menu machine to this canvas
        sm.attachTo(canvas);

        // Machine a état pour le surlignage du menu circulaire
        smMenu = new HighLightMachine(canvas);    

        // Machine a état pour le dessin libre
        smFreeDraw = new FreeDrawMachine(canvas, this);

        // Machine a etat pour le pieMenu
        smPieMenu = new PieMenuMachine(canvas, this);

        // Machine a état pour la selection/déplacement de figures
        smSelectMove = new SelectMoveMachine(canvas, this);
    }

    /**
     * Agencement des composants
     */
    private void placeComponents() {
		// On ajoute la barre de menu
		setJMenuBar(_menu);

        // On choisi un BorderLayout pour afficher: Toolbar (NORTH), Canvas (CENTER), Barre de statut (SOUTH)
        setLayout(new BorderLayout());

        // On ajoute la Toolbar d'outils
        add(_toolBar, BorderLayout.WEST);

        // On ajoute la Toolbar des couleurs
        add(_toolBarCouleurs, BorderLayout.NORTH);

        // Ajout du Canvas de dessin
        add(canvas, BorderLayout.CENTER);

        // Ajout de la barre de statut
        add(_statusBar, BorderLayout.SOUTH);
    }

    /**
     * Méthode public permettant de recréer le panel de reconnaissance des gestes.
     *  Elle est utilisée par les autres classes pour réafficher le menu lorsque l'user
     *  n'effectue aucune action.
     */
    public void createGestureRecognizedPanel() {
        recognizedGestures(classifier);
    }

    /**
     * Création du panel de reconnaissance des gestes
     * @param classifier Classifier comprenant els gestes reconnus.
     */
    private void recognizedGestures(AbstractClassifier classifier) {

        CRectangle bar = new CRectangle(10.0, 25.0, WIDTH_TOOL * 3, HEIGHT_TOOL);
        CRectangle bar2 = new CRectangle(WIDTH_TOOL * 3, 25.0, WIDTH_TOOL * 3, HEIGHT_TOOL);

        bar.setFillPaint(Color.lightGray).addTag(GESTE_TAG).aboveAll();
        bar2.addTag(GESTE_TAG).aboveAll();
        canvas.addShape(bar).addTag(GESTE_TAG).aboveAll();
        canvas.addShape(bar2).addTag(GESTE_TAG).aboveAll();
        canvas.newText(WIDTH_TOOL * (classifier.getClassesNames().size() + .3), 45, " Geste reconnu : ", new Font("Verdana", Font.PLAIN, 14)).addTag(GESTE_TAG).aboveAll();

        canvas.newText(10, 10, "Gestes possibles : ").addTag(GESTE_TAG).aboveAll();
        for (int i = 0; i < classifier.getClassesNames().size(); i++) {
            CPolyLine gest = classifier.getRepresentative(classifier.getClassesNames().get(i));
            gest.addTo(canvas).scaleBy(25 / gest.getHeight(), 25 / gest.getWidth()).translateTo(50 + 70 * i, 50).addTag(GESTE_TAG).aboveAll();
            canvas.newText(0, 0, classifier.getClassesNames().get(i)).translateTo(gest.getCenterX(), bar.getMaxY() - 10).addTag(GESTE_TAG).aboveAll();
        }
    }

    /**
     * Cache les figures avec le tag <i>tag</i>
     * @param tag TAG des figures à cacher
     */
    public void hideShapes(String tag) {
        canvas.getTag(tag).setDrawable(false);
    }

    /**
     * Affiche les figures avec le tag <i>tag</i>
     * @param tag TAG des figures à afficher
     */
    public void showShapes(String tag) {
        canvas.getTag(tag).setDrawable(true).aboveAll();
    }

    /**
     * Supprime les shapes ayant le TAG donné en argument
     */
    public void deleteShapes(String tag) {
        canvas.removeShapes(canvas.getTag(tag));
    }

    /**
     * Définit la couleur a utiliser pour dessiner.
     * @param c Nouvelle couleur utilisée pour le dessin
     */
    public void setBorderColor(Color c) {
        _borderColor = c;
    }
    /**
     * Définit la couleur a utiliser pour le remplissage des figures.
     * @param c Nouvelle couleur utilisée pour le dessin
     */
    public void setBackgroundColor(Color c) {
        _backgroundColor = c;
    }


    /**
     * Méthode permettant de savoir si une shape du canvas possède le tag en argument
     * @param tag - Le tag recherché
     * @return  <b>True</b> si le canvas contient une shape avec le tag donné en argument. <b>False</b> sinon
     */
    public boolean canvasHasTag(String tag) {
        for(CShape shape: canvas.getDisplayList()) {
            if (shape.hasTag(tag))
                return true;
        }
        return false;
    }

    /**
     * Retourne le mode sélectionné dans la barre d'outil.
     * @return  <b>MODE_DESSIN_LIBRE</b> : Les courbes dessinées par l'user sont conservées.
     *          <br> Dans ce mode, les gestes ne sont pas reconnus.
     *          <br>
     *          <b>MODE_SELECT_DEPLACE</b> : L'user peut cliquer sur des shapes pour les sélectionner
     *          et y effectuer des opérations (Copie, Suppression, ..).
     *          <br>
     *          Il peut aussi les déplacer (drag&drop).
     *          <b>MODE_ASSISTE</b> : Les gestes sont reconnus par l'application et le dessin voulu par l'user est réalisé.
     *
     */
    public int drawMode() {
        if (_toolBar.getButton(ToolBarOutils.ID_CRAYON).isSelected())
            return MODE_DESSIN_LIBRE;
        else if (_toolBar.getButton(ToolBarOutils.ID_SELECTIONNER_DEPLACER).isSelected())
            return MODE_SELECT_DEPLACE;
        else if (_toolBar.getButton(ToolBarOutils.ID_ASSISTE).isSelected())
            return MODE_ASSISTE;
        else
            return -1;
    }

    public static void main(String[] args) {
        GestureRecognition gr = new GestureRecognition();
        gr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }


}


